import os
import uuid
from typing import Optional, Tuple
from fastapi import UploadFile, HTTPException
from ..core.config import settings
import logging

logger = logging.getLogger(__name__)

class OSSService:
    
    def __init__(self):
        self.provider = settings.OSS_PROVIDER
        self._init_client()
    
    def _init_client(self):
        if self.provider == "aliyun":
            self._init_aliyun_client()
        elif self.provider == "tencent":
            self._init_tencent_client()
        else:
            raise ValueError(f"Unsupported OSS provider: {self.provider}")
    
    def _init_aliyun_client(self):
        try:
            import oss2
            auth = oss2.Auth(settings.OSS_ACCESS_KEY, settings.OSS_SECRET_KEY)
            self.client = oss2.Bucket(auth, settings.OSS_ENDPOINT, settings.OSS_BUCKET)
            logger.info("阿里云OSS客户端初始化成功")
        except ImportError:
            raise ImportError("请安装阿里云OSS SDK: pip install oss2")
        except Exception as e:
            logger.error(f"阿里云OSS客户端初始化失败: {e}")
            raise
    
    def _init_tencent_client(self):
        try:
            from qcloud_cos import CosConfig, CosS3Client
            config = CosConfig(
                Region=settings.OSS_REGION,
                SecretId=settings.OSS_ACCESS_KEY,
                SecretKey=settings.OSS_SECRET_KEY,
                Scheme='https'
            )
            self.client = CosS3Client(config)
            logger.info("腾讯云COS客户端初始化成功")
        except ImportError:
            raise ImportError("请安装腾讯云COS SDK: pip install cos-python-sdk-v5")
        except Exception as e:
            logger.error(f"腾讯云COS客户端初始化失败: {e}")
            raise
    
    def _generate_file_key(self, filename: str, file_type: str = "general") -> str:
        # 获取文件扩展名
        file_ext = os.path.splitext(filename)[1].lower()
        # 生成唯一文件名
        unique_filename = f"{uuid.uuid4().hex}{file_ext}"
        # 根据文件类型生成存储路径
        file_key = f"{file_type}/{unique_filename}"
        return file_key
    
    def _validate_file(self, file: UploadFile) -> None:
        # 检查文件大小
        if hasattr(file, 'size') and file.size > settings.OSS_MAX_FILE_SIZE:
            raise HTTPException(
                status_code=413,
                detail=f"文件大小超过限制 {settings.OSS_MAX_FILE_SIZE / 1024 / 1024}MB"
            )
        
        # 检查文件类型
        if file.content_type not in settings.OSS_ALLOWED_CONTENT_TYPES:
            raise HTTPException(
                status_code=415,
                detail=f"不支持的文件类型: {file.content_type}"
            )
    
    async def upload_file(
        self, 
        file: UploadFile, 
        file_type: str = "general",
        validate: bool = True
    ) -> Tuple[str, str]:

        if validate:
            self._validate_file(file)
        
        file_key = self._generate_file_key(file.filename, file_type)
        
        try:
            # 读取文件内容
            file_content = await file.read()
            
            if self.provider == "aliyun":
                return await self._upload_to_aliyun(file_key, file_content, file.content_type)
            elif self.provider == "tencent":
                return await self._upload_to_tencent(file_key, file_content, file.content_type)
                
        except Exception as e:
            logger.error(f"文件上传失败: {e}")
            raise HTTPException(status_code=500, detail=f"文件上传失败: {str(e)}")
        finally:
            # 重置文件指针
            await file.seek(0)
    
    async def _upload_to_aliyun(self, file_key: str, file_content: bytes, content_type: str) -> Tuple[str, str]:
        try:
            # 上传文件
            self.client.put_object(
                file_key, 
                file_content,
                headers={'Content-Type': content_type}
            )
            
            # 生成访问URL
            if settings.OSS_CUSTOM_DOMAIN:
                file_url = f"https://{settings.OSS_CUSTOM_DOMAIN}/{file_key}"
            else:
                file_url = f"https://{settings.OSS_BUCKET}.{settings.OSS_ENDPOINT}/{file_key}"
            
            logger.info(f"文件上传到阿里云OSS成功: {file_key}")
            return file_key, file_url
            
        except Exception as e:
            logger.error(f"阿里云OSS上传失败: {e}")
            raise
    
    async def _upload_to_tencent(self, file_key: str, file_content: bytes, content_type: str) -> Tuple[str, str]:
        try:
            # 上传文件
            response = self.client.put_object(
                Bucket=settings.OSS_BUCKET,
                Body=file_content,
                Key=file_key,
                ContentType=content_type
            )
            
            # 生成访问URL
            if settings.OSS_CUSTOM_DOMAIN:
                file_url = f"https://{settings.OSS_CUSTOM_DOMAIN}/{file_key}"
            else:
                file_url = f"https://{settings.OSS_BUCKET}.cos.{settings.OSS_REGION}.myqcloud.com/{file_key}"
            
            logger.info(f"文件上传到腾讯云COS成功: {file_key}")
            return file_key, file_url
            
        except Exception as e:
            logger.error(f"腾讯云COS上传失败: {e}")
            raise
    
    def delete_file(self, file_key: str) -> bool:
        try:
            if self.provider == "aliyun":
                self.client.delete_object(file_key)
            elif self.provider == "tencent":
                self.client.delete_object(
                    Bucket=settings.OSS_BUCKET,
                    Key=file_key
                )
            
            logger.info(f"文件删除成功: {file_key}")
            return True
            
        except Exception as e:
            logger.error(f"文件删除失败: {e}")
            return False
    
    def get_file_url(self, file_key: str, expires: int = 3600) -> str:
        try:
            if self.provider == "aliyun":
                return self.client.sign_url('GET', file_key, expires)
            elif self.provider == "tencent":
                return self.client.get_presigned_url(
                    Method='GET',
                    Bucket=settings.OSS_BUCKET,
                    Key=file_key,
                    Expired=expires
                )
        except Exception as e:
            logger.error(f"生成签名URL失败: {e}")
            raise HTTPException(status_code=500, detail="生成文件访问URL失败")

# 全局OSS服务实例
oss_service = None

def get_oss_service() -> OSSService:
    global oss_service
    if oss_service is None:
        oss_service = OSSService()
    return oss_service 